package com.jt.www.biz.order_pc.service.impl;

import com.jt.www.enums.endorse.GradeEnum;
import com.jt.www.enums.endorse.PdTypeEnum;
import com.jt.www.model.reps.GenericListResponse;
import com.jt.www.model.vo.endorse.CheckNumVO;
import com.jt.www.model.vo.endorse.EduInsuredInfo;
import com.jt.www.model.vo.endorse.EduInsuredObject;
import com.jt.www.model.vo.endorse.EduQueryEndorsementTypeAndCountInfo;
import com.jt.www.model.woxuebao.toubao.ContextExtend;
import com.jt.www.remote.PolClient;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 计算实责批单需要付费人数
 *
 * @author admin_ltf
 * @create 2019-06-25 10:23
 */
@Service
public class EndorseCheckXZNumNewService {

    public static final Logger log = LoggerFactory.getLogger(EndorseCheckXZNumNewService.class);
    private static final String SZ_PRODUCT_CODE = "19PR789827";
    private static final String XZ_PRODUCT_CODE = "19PR961660";
    @Autowired
    private PolClient polClient;
    @Value("${jtpf.benefit-rate}")
    private String benefitRate;

    // 和前端沟通，需要返回  按照险种人数的汇总。举例：双附加险 1人，只买附加险A的1人。返回 双附加险1人  附加险A2人。
    public List<CheckNumVO> checkQGSZNum(List<CheckNumVO> paramList) throws Exception {
        Integer originalNum = paramList.get(0).getOriginalNum();
        Integer currentNum = paramList.get(0).getCurrentNum();
        String type = PdTypeEnum.getValueByPdType(paramList.get(0).getType());
        String policyNo = paramList.get(0).getPolicyNo();
        String productCode = paramList.get(0).getProCode();
        if ("no".equals(type)) {
            return paramList;
        }
        /**
         * 调用批单中心接口，查询批单记录
         */
        //历史参与批单总人数
        Integer totalNum = 0;
        log.info("调用批单中心开始：入参policyNo={}", policyNo);
        ResponseEntity<GenericListResponse<EduQueryEndorsementTypeAndCountInfo>> genericListResponseResponseEntity = polClient.queryEduEndorsemenstInfo(policyNo);
        log.info("调用批单中心结束：出参={}", genericListResponseResponseEntity);
        if (genericListResponseResponseEntity != null) {
            GenericListResponse<EduQueryEndorsementTypeAndCountInfo> body = genericListResponseResponseEntity.getBody();
            String code = body.getCode();
            String valueByPdType = "";
            if ("0000".equals(code)) {
                // 如果本次是批加。那么从记录中只取批加的记录。
                List<EduQueryEndorsementTypeAndCountInfo> list = body.getList();
                if (list != null && list.size() > 0) {
                    for (EduQueryEndorsementTypeAndCountInfo vo : list) {
                        // 先判断类型  然后这一个对象中 所有的数据都是这一个类型  ok
                        String endorsementsType = vo.getEndorsementsType();
                        //不影响批改人数优惠的批改类型 直接跳过
                        if (Arrays.asList("01", "04", "11", "12", "13", "14").contains(endorsementsType)) {
                            continue;
                        }
                        //批改类型转换
                        valueByPdType = PdTypeEnum.getValueByPdType(endorsementsType);
                        if (type.equals(valueByPdType)) {
                            // S_O_000019 学生年级 one two three four five 就这5个年级
                            List<EduInsuredInfo> insuredList = vo.getInsuredList();
                            if (insuredList != null && !insuredList.isEmpty()) {
                                for (EduInsuredInfo eduInsuredInfo : insuredList) {
                                    List<EduInsuredObject> insuranceObjects = eduInsuredInfo.getInsuranceObjects();
                                    if (insuranceObjects != null && insuranceObjects.size() > 0) {
                                        for (EduInsuredObject eduInsuredObject : insuranceObjects) {
                                            List<ContextExtend> extendList = eduInsuredObject.getExtendList();
                                            if (extendList != null && extendList.size() > 0) {
                                                for (ContextExtend contextExtend : extendList) {
                                                    String key = contextExtend.getKey();

                                                    if ("S_O_100004".equals(key)) {
                                                        String value = contextExtend.getValue();
                                                        if (StringUtils.isEmpty(value)) {
                                                            value = "0";
                                                        }
                                                        Integer num = Integer.valueOf(value);
                                                        if ("03".equals(endorsementsType)) {
                                                            totalNum += num;
                                                        } else if ("02".equals(endorsementsType)) {
                                                            totalNum += num;
                                                        } else if ("05".equals(endorsementsType)) {
                                                            log.info("有过协议批加的记录，原保单人数增加");
                                                            originalNum += num;
                                                        } else if ("06".equals(endorsementsType)) {
                                                            log.info("有过协议批减的记录，原保单人数减少");
                                                            originalNum -= num;
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            } else {
                throw new Exception("调用批单中心查询批单记录失败");
            }
        }
        // 第二步：原始人数乘以优惠率  计算应该优惠的人数 num
        Double rate = Double.valueOf(benefitRate);
        // 四舍五入
        Long round = Math.round(originalNum * rate);
        //这张保单应该优惠的总人数
        int num = round.intValue();
        // 本次可以优惠人数
        int subNum = num - totalNum;
        return calculateTwoNumNew(paramList, subNum, StringUtils.equals("add", type) ? (byte) 7 : (byte) 0, 0, new HashMap<>(), StringUtils.equals("add", type) ? "X" : "Y", type, productCode);
    }

    /**
     * 实责 人数处理
     *
     * @param resultList
     * @param subNum
     * @param grade
     * @param highGradeNum
     * @param map
     * @return
     */
    private List<CheckNumVO> calculateTwoNumNew(List<CheckNumVO> resultList, int subNum, byte grade, Integer highGradeNum, Map<String, Integer> map, String type, String endorsementsType, String productCode) {

        // todo  计算实责：实责有两个附加险：实习无过失，附加被保险人。
        // FIXME 获取到传参中的数据 先扣除有两个附加险的，再扣除实习无过失，附加被保险人，从高年级先扣。
        // 该方法  是  计算 两个附加险的
        if (highGradeNum != null && highGradeNum > 0) {
            int i = subNum - highGradeNum;
            if (i > 0) {
                //返回值赋值
                GetNumOfDiscountByRiskType(resultList, grade, highGradeNum, type, productCode);
                //剩余优惠人数
                subNum = subNum - highGradeNum;
                //下一个年级
                if (StringUtils.equals(endorsementsType, "add")) {
                    grade -= 1;
                } else {
                    grade += 1;
                }
                String gradeCode = GradeEnum.getEnCodeByCode(grade);
                highGradeNum = map.get(gradeCode);
                if (StringUtils.equals(endorsementsType, "add")) {
                    if (grade > 0) {
                        calculateTwoNumNew(resultList, subNum, grade, highGradeNum, map, type, endorsementsType, productCode);
                    } else {
                        return resultList;
                    }
                } else {
                    if (grade < 8) {
                        calculateTwoNumNew(resultList, subNum, grade, highGradeNum, map, type, endorsementsType, productCode);
                    } else {
                        return resultList;
                    }
                }
            } else {
                GetNumOfDiscountByRiskType(resultList, grade, subNum, type, productCode);
            }
        } else {
            // 去找下一年级
            if (StringUtils.equals(endorsementsType, "add")) {
                grade -= 1;
                String gradeCode = GradeEnum.getEnCodeByCode(grade);
                // 最高年级的两个附加险的人数
                highGradeNum = map.get(gradeCode);
                if (highGradeNum == null) {
                    highGradeNum = 0;
                }
                if (grade > 0) {
                    return calculateTwoNumNew(resultList, subNum, grade, highGradeNum, map, type, endorsementsType, productCode);
                }
                if (subNum > 0) {
                    //下一个险种组合
                    if (StringUtils.equals(endorsementsType, "add")) {
                        if (StringUtils.equals(type, "D") || StringUtils.equals(type, "J")) {
                            return resultList;
                        }
                    } else {
                        if (StringUtils.equals(type, "A") || StringUtils.equals(type, "E")) {
                            return resultList;
                        }
                    }
                    type = getRiskTypeByEndType(type, endorsementsType, productCode);
                    // 说明 扣完双附加险 的人数后 ，优惠名额还有剩余，需要继续递归循环，去循环 实习无过失的人数，也是从高年级向低年级依次扣
                    // 首先组装一个 所有年级人数的map
                    map = getNumMapByRiskType(resultList, type, productCode);
                    if (StringUtils.equals(endorsementsType, "add")) {
                        grade = 7;
                    } else {
                        grade = 1;
                    }
                    gradeCode = GradeEnum.getEnCodeByCode(grade);
                    // 最高年级的只买 实习无过失 的人数
                    highGradeNum = map.get(gradeCode);
                    if (highGradeNum == null) {
                        highGradeNum = 0;
                    }
                    return calculateTwoNumNew(resultList, subNum, grade, highGradeNum, map, type, endorsementsType, productCode);
                }
            } else {
                grade += 1;
                String gradeCode = GradeEnum.getEnCodeByCode(grade);
                // 最高年级的两个附加险的人数
                highGradeNum = map.get(gradeCode);
                if (highGradeNum == null) {
                    highGradeNum = 0;
                }
                if (grade < 8) {
                    return calculateTwoNumNew(resultList, subNum, grade, highGradeNum, map, type, endorsementsType, productCode);
                }
                if (subNum > 0) {
                    if (StringUtils.equals(endorsementsType, "add")) {
                        if (StringUtils.equals(type, "D") || StringUtils.equals(type, "J")) {
                            return resultList;
                        }
                    } else {
                        if (StringUtils.equals(type, "A") || StringUtils.equals(type, "E")) {
                            return resultList;
                        }
                    }
                    //下一个险种组合
                    type = getRiskTypeByEndType(type, endorsementsType, productCode);
                    // 说明 扣完双附加险 的人数后 ，优惠名额还有剩余，需要继续递归循环，去循环 实习无过失的人数，也是从高年级向低年级依次扣
                    // 首先组装一个 所有年级人数的map
                    map = getNumMapByRiskType(resultList, type, productCode);
                    if (StringUtils.equals(endorsementsType, "add")) {
                        grade = 7;
                    } else {
                        grade = 0;
                    }
                    gradeCode = GradeEnum.getEnCodeByCode(grade);
                    // 最高年级的只买 实习无过失 的人数
                    highGradeNum = map.get(gradeCode);
                    if (highGradeNum == null) {
                        highGradeNum = 0;
                    }
                    return calculateTwoNumNew(resultList, subNum, grade, highGradeNum, map, type, endorsementsType, productCode);
                }
            }

        }
        return resultList;
    }

    /**
     * 根据批改类型和险种组合的优先级获取险种组合
     * 规则优先级：批减sub：D-C-B-A
     * 批增add：A-B-C-D
     *
     * @param type             A-双附加  B-附加实习无过失 C-附加被保险人  D-主险
     * @param endorsementsType
     * @return
     */
    private String getRiskTypeByEndType(String type, String endorsementsType, String productCode) {
        switch (productCode) {
            case SZ_PRODUCT_CODE://实责
                if (StringUtils.equals(endorsementsType, "add")) {
                    if (StringUtils.equals(type, "X")) {
                        type = "A";
                    } else if (StringUtils.equals(type, "A")) {
                        type = "B";
                    } else if (StringUtils.equals(type, "B")) {
                        type = "C";
                    } else if (StringUtils.equals(type, "C")) {
                        type = "D";
                    }
                } else {
                    if (StringUtils.equals(type, "Y")) {
                        type = "D";
                    } else if (StringUtils.equals(type, "D")) {
                        type = "C";
                    } else if (StringUtils.equals(type, "C")) {
                        type = "B";
                    } else if (StringUtils.equals(type, "B")) {
                        type = "A";
                    }
                }
                break;
            case XZ_PRODUCT_CODE://校责
                if (StringUtils.equals(endorsementsType, "add")) {
                    if (StringUtils.equals(type, "X")) {
                        type = "E";
                    } else if (StringUtils.equals(type, "E")) {
                        type = "F";
                    } else if (StringUtils.equals(type, "F")) {
                        type = "G";
                    } else if (StringUtils.equals(type, "G")) {
                        type = "H";
                    } else if (StringUtils.equals(type, "H")) {
                        type = "I";
                    } else if (StringUtils.equals(type, "I")) {
                        type = "J";
                    }
                } else {
                    if (StringUtils.equals(type, "Y")) {
                        type = "J";
                    } else if (StringUtils.equals(type, "J")) {
                        type = "I";
                    } else if (StringUtils.equals(type, "I")) {
                        type = "H";
                    } else if (StringUtils.equals(type, "H")) {
                        type = "G";
                    } else if (StringUtils.equals(type, "G")) {
                        type = "F";
                    } else if (StringUtils.equals(type, "F")) {
                        type = "E";
                    }
                }
                break;
        }
        return type;
    }

    /**
     * 每个险种对应的优惠人数
     *
     * @param resultList
     * @param grade
     * @param discountNum
     * @param type
     */
    private void GetNumOfDiscountByRiskType(List<CheckNumVO> resultList, byte grade, Integer discountNum, String type, String productCode) {
        switch (productCode) {
            case SZ_PRODUCT_CODE://实责
                switch (type) {
                    case "A"://双附加
                        for (CheckNumVO checkNumVO : resultList) {
                            if (StringUtils.equals(GradeEnum.getEnCodeByCode(grade), checkNumVO.getGrade())) {
                                if (checkNumVO.getSxAInsMfNum() != null && checkNumVO.getSxAInsMfNum().compareTo(0) > 0) {
                                    checkNumVO.setSxAInsMfNum(checkNumVO.getSxAInsMfNum() + discountNum);
                                } else {
                                    checkNumVO.setSxAInsMfNum(discountNum);
                                }
                            }
                        }
                        break;
                    case "B"://附加实习无过失
                        for (CheckNumVO checkNumVO : resultList) {
                            if (StringUtils.equals(GradeEnum.getEnCodeByCode(grade), checkNumVO.getGrade())) {
                                if (checkNumVO.getInsSxMfNum() != null && checkNumVO.getInsSxMfNum().compareTo(0) > 0) {
                                    checkNumVO.setInsSxMfNum(checkNumVO.getInsSxMfNum() + discountNum);
                                } else {
                                    checkNumVO.setInsSxMfNum(discountNum);
                                }

                            }
                        }
                        break;
                    case "C"://附加被保险人
                        for (CheckNumVO checkNumVO : resultList) {
                            if (StringUtils.equals(GradeEnum.getEnCodeByCode(grade), checkNumVO.getGrade())) {
                                if (checkNumVO.getInsMfNum() != null && checkNumVO.getInsMfNum().compareTo(0) > 0) {
                                    checkNumVO.setInsMfNum(checkNumVO.getInsMfNum() + discountNum);
                                } else {
                                    checkNumVO.setInsMfNum(discountNum);
                                }
                            }
                        }
                        break;
                    case "D"://主险
                        for (CheckNumVO checkNumVO : resultList) {
                            if (StringUtils.equals(GradeEnum.getEnCodeByCode(grade), checkNumVO.getGrade())) {
                                if (checkNumVO.getInsNum5() != null && checkNumVO.getInsNum5().compareTo(0) > 0) {
                                    checkNumVO.setInsNum5(checkNumVO.getInsNum5() + discountNum);
                                } else {
                                    checkNumVO.setInsNum5(discountNum);
                                }
                            }
                        }
                        break;
                }
                break;
            case XZ_PRODUCT_CODE://校责
                switch (type) {
                    case "E"://校方+校外+传染病
                        for (CheckNumVO checkNumVO : resultList) {
                            if (StringUtils.equals(GradeEnum.getEnCodeByCode(grade), checkNumVO.getGrade())) {
                                if (checkNumVO.getXz1MFNum() != null && checkNumVO.getXz1MFNum().compareTo(0) > 0) {
                                    checkNumVO.setXz1MFNum(checkNumVO.getXz1MFNum() + discountNum);
                                } else {
                                    checkNumVO.setXz1MFNum(discountNum);
                                }
                            }
                        }
                        break;
                    case "F"://校方+校外
                        for (CheckNumVO checkNumVO : resultList) {
                            if (StringUtils.equals(GradeEnum.getEnCodeByCode(grade), checkNumVO.getGrade())) {
                                if (checkNumVO.getXz2MFNum() != null && checkNumVO.getXz2MFNum().compareTo(0) > 0) {
                                    checkNumVO.setXz2MFNum(checkNumVO.getXz2MFNum() + discountNum);
                                } else {
                                    checkNumVO.setXz2MFNum(discountNum);
                                }

                            }
                        }
                        break;
                    case "G"://校方+传染病
                        for (CheckNumVO checkNumVO : resultList) {
                            if (StringUtils.equals(GradeEnum.getEnCodeByCode(grade), checkNumVO.getGrade())) {
                                if (checkNumVO.getXz3MFNum() != null && checkNumVO.getXz3MFNum().compareTo(0) > 0) {
                                    checkNumVO.setXz3MFNum(checkNumVO.getXz3MFNum() + discountNum);
                                } else {
                                    checkNumVO.setXz3MFNum(discountNum);
                                }
                            }
                        }
                        break;
                    case "H"://校方
                        for (CheckNumVO checkNumVO : resultList) {
                            if (StringUtils.equals(GradeEnum.getEnCodeByCode(grade), checkNumVO.getGrade())) {
                                if (checkNumVO.getXzMfNum() != null && checkNumVO.getXzMfNum().compareTo(0) > 0) {
                                    checkNumVO.setXzMfNum(checkNumVO.getXzMfNum() + discountNum);
                                } else {
                                    checkNumVO.setXzMfNum(discountNum);
                                }
                            }
                        }
                        break;
                    case "I"://传染病
                        for (CheckNumVO checkNumVO : resultList) {
                            if (StringUtils.equals(GradeEnum.getEnCodeByCode(grade), checkNumVO.getGrade())) {
                                if (checkNumVO.getXzcrbMFNum() != null && checkNumVO.getXzcrbMFNum().compareTo(0) > 0) {
                                    checkNumVO.setXzcrbMFNum(checkNumVO.getXzcrbMFNum() + discountNum);
                                } else {
                                    checkNumVO.setXzcrbMFNum(discountNum);
                                }
                            }
                        }
                        break;
                    case "J"://主险
                        for (CheckNumVO checkNumVO : resultList) {
                            if (StringUtils.equals(GradeEnum.getEnCodeByCode(grade), checkNumVO.getGrade())) {
                                if (checkNumVO.getXzNum3() != null && checkNumVO.getXzNum3().compareTo(0) > 0) {
                                    checkNumVO.setXzNum3(checkNumVO.getXzNum3() + discountNum);
                                } else {
                                    checkNumVO.setXzNum3(discountNum);
                                }
                            }
                        }
                        break;
                }
                break;
        }

    }

    /**
     * 获取指定险种组合下每个年级的人数
     *
     * @param resultList
     * @param type       A-双附加 B-附加实习无过失   C- 附加被保险人 D-主险
     * @return
     */
    private Map<String, Integer> getNumMapByRiskType(List<CheckNumVO> resultList, String type, String productCode) {

        Map<String, Integer> map = new HashMap<>();
        switch (productCode) {
            case SZ_PRODUCT_CODE://实责
                switch (type) {
                    case "A":
                        for (CheckNumVO checkNumVO : resultList) {
                            String nj = checkNumVO.getGrade();
                            Integer insNum1 = checkNumVO.getInsNum3();
                            map.put(nj, insNum1);
                        }
                        break;
                    case "B":
                        for (CheckNumVO checkNumVO : resultList) {
                            String nj = checkNumVO.getGrade();
                            Integer insNum1 = checkNumVO.getInsNum1();
                            map.put(nj, insNum1);
                        }
                        break;
                    case "C":
                        for (CheckNumVO checkNumVO : resultList) {
                            String nj = checkNumVO.getGrade();
                            Integer insNum2 = checkNumVO.getInsNum2();
                            map.put(nj, insNum2);
                        }
                        break;
                    case "D":
                        for (CheckNumVO checkNumVO : resultList) {
                            String nj = checkNumVO.getGrade();
                            Integer insNum4 = checkNumVO.getInsNum4();
                            map.put(nj, insNum4);
                        }
                        break;
                }
                break;
            case XZ_PRODUCT_CODE://校责
                switch (type) {
                    case "E"://校方+校外+传染病
                        for (CheckNumVO checkNumVO : resultList) {
                            String nj = checkNumVO.getGrade();
                            map.put(nj, checkNumVO.getXz1Num());
                        }
                        break;
                    case "F"://校方+校外
                        for (CheckNumVO checkNumVO : resultList) {
                            String nj = checkNumVO.getGrade();
                            map.put(nj, checkNumVO.getXz2Num());
                        }
                        break;
                    case "G"://校方+传染病
                        for (CheckNumVO checkNumVO : resultList) {
                            String nj = checkNumVO.getGrade();
                            map.put(nj, checkNumVO.getXz3Num());
                        }
                        break;
                    case "H"://校方
                        for (CheckNumVO checkNumVO : resultList) {
                            String nj = checkNumVO.getGrade();
                            map.put(nj, checkNumVO.getXzNum1());
                        }
                        break;
                    case "I"://传染病
                        for (CheckNumVO checkNumVO : resultList) {
                            String nj = checkNumVO.getGrade();
                            map.put(nj, checkNumVO.getXzcrbNum());
                        }
                        break;
                    case "J"://主险
                        for (CheckNumVO checkNumVO : resultList) {
                            String nj = checkNumVO.getGrade();
                            map.put(nj, checkNumVO.getXzNum2());
                        }
                        break;
                }
                break;
        }
        return map;
    }

}
